# 批量梯度下降法实现线性回归
import numpy as np

# ==================== 数据准备阶段 ====================
# 设置随机种子保证每次运行结果一致
np.random.seed(1)

# 生成特征数据X：100个样本，每个样本1个特征，取值范围[0,2)
X = 2 * np.random.rand(100, 1)

# 生成标签数据y：真实模型为y=4+3X+噪声
# 4是截距(bias)，3是权重(weight)，噪声服从标准正态分布
y = 4 + 3 * X + np.random.randn(100, 1)

# 为X添加一列全1的偏置项(bias term)，方便向量化计算
# 这样可以将截距和权重统一用theta向量表示
X_b = np.c_[np.ones((100, 1)), X]  # shape: (100, 2)

# ==================== 超参数设置 ====================
learning_rate = 0.1  # 学习率，控制参数更新步长
n_iterations = 1000   # 迭代次数

# ==================== 模型参数初始化 ====================
# 随机初始化参数theta，包含截距(theta0)和斜率(theta1)
# 使用标准正态分布初始化，shape为(2,1)
theta = np.random.randn(2, 1)

# ==================== 梯度下降迭代 ====================
for iteration in range(n_iterations):
    # 计算梯度：
    gradients = (1 / len(X_b)) * X_b.T.dot(X_b.dot(theta) - y)

    # 参数更新：
    # 沿着梯度反方向调整参数，学习率控制步长
    theta = theta - learning_rate * gradients

    # 每10次迭代打印当前参数和损失
    if iteration % 100 == 0:
        loss = np.mean((X_b.dot(theta) - y) ** 2)
        print(f"Iter {iteration}: theta={theta.T}, loss={loss:.4f}")

# ==================== 输出最终参数 ====================
# 打印训练后得到的参数，应该接近真实值[4,3]
print("训练得到的参数:")
print(theta.T)
